package com.item.redis.annocation;

import com.item.entity.WxUser;
import com.item.exception.common.CustomException;
import java.util.concurrent.TimeUnit;
import com.item.redis.RedisUtil;
import com.item.util.Constant;
import com.item.util.RequestsUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

/**
 * @author zhang-rongyao
 * @version V1.0
 * @Package com.item.model.annocation
 * @date 2021/7/22 16:49
 */
@Aspect
@Component
public class ApiTokenAop {

    private static final Logger log = LoggerFactory.getLogger(ApiTokenAop.class);

    @Autowired
    RedisUtil redisUtil;

    //1.使用aop环绕通知拦截所有controller
    @Pointcut(value = "execution(public * com.item.controller.*.*(..))")
    public void access() {
    }

    @Before("access()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
    }


    @Around("@annotation(apiToken)")
    public Object around(ProceedingJoinPoint pjp, ApiToken apiToken) throws Throwable {
        // TODO Auto-generated method stub
        //2.判断方法上是否有注解@ApiToken
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method =signature.getMethod();
        String methodName = method.getName();
        ApiToken declaredAnnotation = method.getDeclaredAnnotation(ApiToken.class);
        //3.有注解
        if (declaredAnnotation!=null){
            String type = declaredAnnotation.sign();
            int expireTime = declaredAnnotation.expireTime();
            //4.组织redisKey：uerID+"_"+type+"_"+methodName+"_"+方法参数
            HttpServletRequest request = RequestsUtil.getHttpServletRequest();
            HttpSession session = request.getSession();
            //a.获取userId
            WxUser user = (WxUser) session.getAttribute("user");
            Object[] args = pjp.getArgs();
            //b.获取方法的所有参数名
            StringBuilder methodParamsName = new StringBuilder();
            Parameter[] parameters = method.getParameters();
            for(int i = 0;i< parameters.length;i++){
                Parameter parameter = parameters[i];
                if(null != args[i]){
                    methodParamsName.append("_").append(parameter.getName());
                }
            }
            String token = type+"_"+methodName+"_"+user.getId().toString()+methodParamsName;

            //查询redis中有没有这个key,如果有则当前用户2秒内提交过相同的表单
            Boolean hasSaveKey = redisUtil.hasKey(token);
            if (hasSaveKey) {
                throw new CustomException("操作太频繁了");
            }

            redisUtil.setEx(token,"",expireTime,TimeUnit.MILLISECONDS);

            try{
                return pjp.proceed();
            }catch (Throwable throwable){
                Long del = redisUtil.delete(Arrays.asList(token));
                if (del <= 0) {
                    throw new CustomException("token 清除失败");
                }
            }
        }

        //放行
        return pjp.proceed();
    }


}